﻿using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Web;
using MaxAlarm.Common.WebQueries;

namespace MaxAlarm.Core.WebQueries
{
    public abstract class WebQuery
    {
        public abstract WebQueryType QueryType { get; }
        public WebQueryResult Result { get; protected set; }

        #region Private properties

        protected readonly string Cookies;
        protected NameValueCollection QueryData;

        #endregion

        #region Constants

        protected const string UserAgent =
            "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; .NET CLR 1.1.4322; .NET CLR 2.0.50727; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729; .NET4.0C; .NET4.0E)";

        protected const string ContentType = "application/x-www-form-urlencoded";

        protected const string Accept =
            "image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/x-ms-application, application/x-ms-xbap, application/vnd.ms-xpsdocument, application/xaml+xml, application/msword, application/vnd.ms-excel, application/vnd.ms-powerpoint, */*";

        #endregion

        protected WebQuery(string address, string cookies, NameValueCollection data)
        {
            Cookies = cookies;
            QueryData = data;

            Result = new WebQueryResult
                         {
                             Address = address,
                             Completed = false
                         };
        }


        public WebQueryResult Execute()
        {
            try
            {
                var client = new WebClient();
                client.Headers.Add(HttpRequestHeader.UserAgent, UserAgent);
                client.Headers.Add(HttpRequestHeader.ContentType, ContentType);
                client.Headers.Add(HttpRequestHeader.AcceptEncoding, "utf-8");
                client.Headers.Add(HttpRequestHeader.AcceptLanguage, "ru");
                client.Headers.Add(HttpRequestHeader.Accept, Accept);
                client.Headers.Add(HttpRequestHeader.Pragma, "no-cache");
                client.Headers.Add(HttpRequestHeader.Cookie, Cookies);
                client.Encoding = Encoding.UTF8;

                Result.Content = SendData(client, Result.Address, QueryData);
                Result.Type = QueryType;
                Result.Cookies = client.ResponseHeaders[HttpResponseHeader.SetCookie];
                Result.Completed = true;
                Result.Status = HttpStatusCode.OK;
                Result.HasError = false;

            }
            catch(WebException we)
            {
                Result.HasError = true;
                var response = (HttpWebResponse) we.Response;
                Result.Status = response == null ? HttpStatusCode.UnsupportedMediaType : response.StatusCode;
                Result.ErrorMessage = we.Message;

                throw;
            }
            catch (Exception e)
            {
                Result.HasError = true;
                Result.ErrorMessage = e.Message;

                throw;
            }

            return Result;
        }

        protected abstract string SendData(WebClient client, string url, NameValueCollection data);

        protected string ToQueryString(NameValueCollection nvc)
        {
            return "?" + string.Join("&", Array.ConvertAll(nvc.AllKeys, key => string.Format("{0}={1}", HttpUtility.UrlEncode(key), HttpUtility.UrlEncode(nvc[key]))));
        }

        public static WebQuery Create(WebQueryType type, string address, string cookies, NameValueCollection data)
        {
            switch (type)
            {
                case WebQueryType.GET:
                    return new WebGetQuery(address, cookies, data);

                case WebQueryType.POST:
                    return new WebPostQuery(address, cookies, data);

                default:
                    throw new ArgumentOutOfRangeException("type");
            }
        }

        public static string GetCookies(string address)
        {
            var webClient = new WebClient();
            webClient.DownloadString(address);
            return webClient.ResponseHeaders[HttpResponseHeader.SetCookie];
        }
    }
}
